package com.lanchetech.admin.service.impl;


import com.alibaba.excel.util.CollectionUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.lanchetech.admin.service.FundService;
import com.lanchetech.bean.request.CommissionRecordPageReq;
import com.lanchetech.bean.request.FreezeAmountReq;
import com.lanchetech.bean.request.PageReq;
import com.lanchetech.bean.response.BasePageResp;
import com.lanchetech.bean.response.BaseResp;
import com.lanchetech.bean.response.ResultData;
import com.lanchetech.bean.util.PageHelpUtil;
import com.lanchetech.bean.vo.*;
import com.lanchetech.common.enums.*;
import com.lanchetech.dao.*;
import com.lanchetech.entity.*;
import com.lanchetech.service.DaoService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.lanchetech.common.constants.JypConstant.HIPO_USER_ID;

@Service
public class FundServiceImpl implements FundService {

    @Autowired
    BalanceFlowMapper balanceFlowMapper;

    @Autowired
    CoinFlowMapper coinFlowMapper;

    @Autowired
    DaoService daoService;

    @Autowired
    CommissionRecordMapper commissionRecordMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    UserCommissionMapper userCommissionMapper;

    @Autowired
    TenantFlowMapper tenantFlowMapper;

    @Autowired
    TenantMapper tenantMapper;

    @Autowired
    TenantWithdrawMapper tenantWithdrawMapper;

    @Autowired
    FreezeAmountMapper freezeAmountMapper;

    @Override
    public ResultData<BasePageResp<BalanceFlowVO>> getBalanceFlowPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<BalanceFlow> list = balanceFlowMapper.findAllPage(req);
        List<BalanceFlowVO> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, User> map = daoService.getUserMap(list.stream().map(BalanceFlow::getUserId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                BalanceFlowVO vo = new BalanceFlowVO();
                BeanUtils.copyProperties(item, vo);
                vo.setNickname(map.get(item.getUserId()).getNickname());
                vo.setAvatar(map.get(item.getUserId()).getAvatar());
                result.add(vo);
            });
        }
        return PageHelpUtil.buildPage(result, page);
    }

    @Override
    public ResultData<BasePageResp<CoinFlowVO>> getCoinFlowPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<CoinFlow> list = coinFlowMapper.findAllPage(req);
        List<CoinFlowVO> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, User> map = daoService.getUserMap(list.stream().map(CoinFlow::getUserId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                CoinFlowVO vo = new CoinFlowVO();
                BeanUtils.copyProperties(item, vo);
                vo.setNickname(map.get(item.getUserId()).getNickname());
                vo.setAvatar(map.get(item.getUserId()).getAvatar());
                result.add(vo);
            });
        }
        return PageHelpUtil.buildPage(result, page);
    }

    @Override
    public ResultData<BasePageResp<CommissionRecordVO>> getCommissionRecordPage(CommissionRecordPageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<CommissionRecord> list = commissionRecordMapper.findAllPage(req);

        List<CommissionRecordVO> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(list)) {
            list.stream().forEach(item -> {
                CommissionRecordVO vo = new CommissionRecordVO();
                BeanUtils.copyProperties(item, vo);
                result.add(vo);
            });
        }
        return PageHelpUtil.buildPage(result, page);
    }

    @Override
    public ResultData<BigDecimal> getCommissionSum(PageReq req) {
        BigDecimal amount = commissionRecordMapper.sumByStatusAndTime(UserCommissionStatusEnum.ISSUED.getStatus(), req.getStartTime(), req.getEndTime());
        return new ResultData<>(amount);
    }

    @Override
    public BaseResp issueCommissionDirect(BigDecimal amount, Long userId) {
        Admin admin = (Admin) SecurityContextHolder.getContext().getAuthentication().getPrincipal();


        userMapper.changePointById(amount, userId);

        User user = userMapper.selectByPrimaryKey(userId);


        if (amount.compareTo(BigDecimal.ZERO) > 0) {
            // 如果被扣除，则有部分余额无法取出
            userCommissionMapper.insert(UserCommission.builder()
                    .superiorId(user.getId())
                    .subordinateId(HIPO_USER_ID)
                    .commission(amount)
                    .type(UserCommissionTypeEnum.MANAGE_ADD.getType())
                    .freezeTime(new Date())
                    .status(UserCommissionStatusEnum.ISSUED.getStatus())
                    .createdAt(new Date())
                    .updatedAt(new Date())
                    .amount(amount)
                    .identityType((byte) -1)
                    .businessType(UserCommissionBusinessTypeEnum.USER.getType())
                    .build());
        }

        // 创建余额使用记录
        TradeTypeEnum type = amount.compareTo(BigDecimal.ZERO) > 0 ? TradeTypeEnum.MANAGE_ADD : TradeTypeEnum.MANAGE_SUB;
        balanceFlowMapper.insert(BalanceFlow.builder()
                .userId(userId)
                .amount(amount.abs())
                .tradeType(type.getTradeType())
                .type(type.getType())
                .point(user.getPoint())
                .remark(admin.getNickname())
                .relateId(admin.getId())
                .createdAt(new Date())
                .build());
        return new BaseResp();
    }

    @Override
    public BaseResp issueCoinDirect(BigDecimal coin, Long userId) {
        Admin admin = (Admin) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        userMapper.changeCoinById(coin, userId);

        User user = userMapper.selectByPrimaryKey(userId);

        // 创建积分使用记录
        CoinFlowTradeTypeEnum type = coin.compareTo(BigDecimal.ZERO) > 0 ? CoinFlowTradeTypeEnum.MANAGE_ADD : CoinFlowTradeTypeEnum.MANAGE_SUB;
        coinFlowMapper.insert(CoinFlow.builder()
                .userId(user.getId())
                .amount(coin.abs())
                .tradeType(type.getTradeType())
                .type(type.getType())
                .coin(user.getCoin())
                .relateId(admin.getId())
                .remark(admin.getNickname())
                .createdAt(new Date())
                .build());
        return new BaseResp();
    }


    @Override
    public ResultData<BasePageResp<TenantWithdrawVO>> getAllTenantWithdrawPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<TenantWithdraw> list = tenantWithdrawMapper.findAllPage(req);
        List<TenantWithdrawVO> voList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, Shop> map = daoService.getShopMap(list.stream().map(TenantWithdraw::getTenantId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                TenantWithdrawVO vo = new TenantWithdrawVO();
                BeanUtils.copyProperties(item, vo);
                vo.setAccount(map.get(item.getTenantId()).getAccount());
                vo.setBank(map.get(item.getTenantId()).getBank());
                vo.setOpenBank(map.get(item.getTenantId()).getOpenBank());
                vo.setName(map.get(item.getTenantId()).getOpenName());
                vo.setTenantNickname(map.get(item.getTenantId()).getShopName());
                voList.add(vo);
            });
        }
        return PageHelpUtil.buildPage(voList, page);
    }

    @Override
    public BaseResp auditTenantWithdraw(TenantWithdrawVO req) {
        TenantWithdraw vo = tenantWithdrawMapper.selectByPrimaryKey(req.getId());
        // 待审核才能审核
        if (TenantWithdrawStatusEnum.PROCESSING.getStatus().equals(vo.getStatus())) {
            // 提现成功
            if (TenantWithdrawStatusEnum.SUCCESS.getStatus().equals(req.getStatus())) {
                // 提现前一定要检查余额
                Tenant tenant = tenantMapper.selectByPrimaryKey(req.getTenantId());
                if (tenant.getPoint().compareTo(vo.getAmount()) >= 0) {
                    // 扣除余额
                    BigDecimal point = tenant.getPoint().subtract(vo.getAmount());
                    tenantMapper.updatePointById(point, tenant.getId());
                    // 更新提现状态
                    tenantWithdrawMapper.updateStatusAndUpdatedAtById(TenantWithdrawStatusEnum.SUCCESS.getStatus(), new Date(), req.getId());
                    // 创建余额流水明细
                    tenantFlowMapper.insert(TenantFlow.builder()
                            .amount(vo.getAmount())
                            .tradeType(TenantTradeTypeEnum.WITHDRAW.getTradeType())
                            .type(TenantTradeTypeEnum.WITHDRAW.getType())
                            .point(point)
                            .relateId(req.getId())
                            .remark("提现"+vo.getAmount().toString()+"元")
                            .createdAt(new Date())
                            .tenantId(tenant.getId())
                            .build());
                } else {
                    return new BaseResp(ResultCode.INSUFFICIENT_BALANCE);
                }
            } else {
                tenantWithdrawMapper.updateStatusAndUpdatedAtById(TenantWithdrawStatusEnum.REFUSE.getStatus(), new Date(), req.getId());
            }
        } else {
            return new BaseResp(ResultCode.FAIL);
        }
        return new BaseResp();
    }

    @Override
    public ResultData<BasePageResp<TenantFlowVO>> getTenantFlowPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<TenantFlow> list = tenantFlowMapper.findAllPage(req);
        List<TenantFlowVO> result = new ArrayList<>();
        if(!CollectionUtils.isEmpty(list)){
            Map<Long, Shop> tenantMap = daoService.getShopMap(list.stream().map(TenantFlow::getTenantId).collect(Collectors.toList()));
            list.stream().forEach(item->{
                TenantFlowVO vo = new TenantFlowVO();
                BeanUtils.copyProperties(item, vo);
                vo.setTenantNickname(tenantMap.get(item.getTenantId()).getShopName());
                vo.setTenantAvatar(tenantMap.get(item.getTenantId()).getAvatar());
                result.add(vo);
            });
        }
        return PageHelpUtil.buildPage(result, page);
    }

    @Override
    public ResultData<BasePageResp<FreezeAmountVO>> getFreezeAmountPage(FreezeAmountReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<FreezeAmountVO> list = freezeAmountMapper.findAllPage(req);
        if(!CollectionUtils.isEmpty(list)){
            Map<Long,Orders> ordersMap = daoService.getOrdersMap(list.stream().map(FreezeAmountVO::getOrderId).collect(Collectors.toList()));
            Map<Long, Shop> tenantMap = daoService.getShopMap(list.stream().map(FreezeAmountVO::getTenantId).collect(Collectors.toList()));
            Map<Long,User> userMap= daoService.getUserMap(ordersMap.values().stream().map(Orders::getUserId).collect(Collectors.toList()));
            list.stream().forEach(item->{
                Orders orders = ordersMap.get(item.getOrderId());
                item.setShopName(tenantMap.get(item.getTenantId()).getShopName());
                item.setOrderRemark(orders.getRemark());
                item.setUserNickname(userMap.get(orders.getUserId()).getNickname());
                item.setUserAvatar(userMap.get(orders.getUserId()).getAvatar());
            });
        }

        ResultData<BasePageResp<FreezeAmountVO>> result = PageHelpUtil.buildPage(list, page);
        result.getValue().setExtra(freezeAmountMapper.sumAmountStatistics(req));
        return result;
    }

}